#include <string>
#include <map>
#include <memory>
#include <functional>
#include <iostream>

template <class T>
class IOCContainer
{
public:
    IOCContainer(void) {}
    ~IOCContainer() {}

    template <class Drived>
    void RegisterType(std::string strKey)
    {
        std::function<T *()> function = []
        { return new Drived(); };
        RegisterType(strKey, function); //将唯一key 和 构建函数 绑定在一起
    }
    T *Resolve(std::string strKey)
    {
        if (m_creatorMap.find(strKey) == m_creatorMap.end())
            return nullptr;
        std::function<T *()> function = m_creatorMap[strKey];
        return function();
    }

    std::shared_ptr<T> ResolveShared(std::string strKey)
    {
        T *ptr = Resolve(strKey);
        return std::shared_ptr<T>(ptr);
    }

private:
    void RegisterType(std::string strKey, std::function<T *()> creator)
    {
        if (m_creatorMap.find(strKey) != m_creatorMap.end())
        {
            throw std::invalid_argument("this key has already exits!");
        }
        m_creatorMap.emplace(strKey, creator); // Inserts a new element in the map if its key is unique
    }

    std::map<std::string, std::function<T *()>> m_creatorMap;
};

struct ICar
{
    virtual ~ICar() {}
    virtual void test() const = 0;
};

struct Bus : ICar
{
    Bus(){}

    void test() const { std::cout << "Bus::test()" << std::endl;}
};

struct Car :ICar
{
    Car(){}
    void test() const {std::cout << "Car::test()" << std::endl;}
};

int main(int argc, char const *argv[])
{
    IOCContainer<ICar> carioc;
    carioc.RegisterType<Bus>("bus");
    carioc.RegisterType<Car>("Car");
    std::shared_ptr<ICar> bus = carioc.ResolveShared("bus");
    bus->test();

    std::shared_ptr<ICar> car = carioc.ResolveShared("Car");
    car->test();
    return 0;
}

/**
 * @brief 上面的例子 可以创建所有的无参数的派生类对象，但存在几个不足之处：
 * 1. 只能创建无参对象，不能创建有参数的对象
 * 2. 只能创建一种接口类型的对象，不能创建所有类型的对象
 * 
 * 如果希望这个工厂能够创建所有对象，则需要通过类型擦除技术来实现。
 * 
 */

